package m2.connector;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;

import m2.role.ProvidedRole;
import m2.role.RequiredRole;
import m2.role.Role;
import tools.Message;

public class Glue implements Observer{

	private ArrayList<Role[]> listeRole = new ArrayList<Role[]>();
	private Method internalComponentProcessing = null;
	private Object componentOrConnector = null;
	
	/**
	 * 
	 * @param providedRole
	 * @param requiredRole
	 */
	public final void connectProvidedRoleToRequiredRole(ProvidedRole providedRole, RequiredRole requiredRole){
		if (verifDifferentTypeRole(requiredRole, providedRole)){
			Role [] bindRole = new Role[2];
			bindRole[0] = requiredRole;			
			bindRole[1] = providedRole;			
			listeRole.add(bindRole);
			((ProvidedRole)bindRole[1]).observBy(this);
		}		
	}
	
	/**
	 * 
	 * @param requiredRole
	 * @param providedRole
	 */
	public final void connectRequiredRoleToProvidedRole(RequiredRole requiredRole, ProvidedRole providedRole){
		if (verifDifferentTypeRole(requiredRole, providedRole)){
			Role [] bindRole = new Role[2];
			bindRole[0] = requiredRole;
			bindRole[1] = providedRole;
			listeRole.add(bindRole);
			((RequiredRole)bindRole[0]).observBy(this);			
		}		
	}
	
	/**
	 * 
	 * @param role
	 * @param pRole
	 * @return
	 */
	private boolean verifDifferentTypeRole(RequiredRole role, ProvidedRole pRole){
		if (role.getType().equals(pRole.getType())){
			Message.putInLogger("Les deux roles doivent etre de types differents");
			return false;
		}
		return true;
	}

	/**
	 * 
	 * @param role
	 * @return
	 */
	private RequiredRole findRequiredRole(Role role){
		for (Role[] roles : listeRole){
			if (role.equals(roles[1])){
				return (RequiredRole)roles[0];
			}
		}
		return null; 
	}
	
	/**
	 * 
	 * @param role
	 * @return
	 */
	private ProvidedRole findProvidedRole(Role role){
		for (Role[] roles : listeRole){
			if (role.equals(roles[0])){
					return (ProvidedRole)roles[1];
			}
		}
		return null; 
	}
	
	/**
	 * 
	 * @param method
	 * @param object
	 */
	public void setGlueProcessing(Method method, Object object){
		this.internalComponentProcessing = method;
		this.componentOrConnector = object;
	}
	
	@Override
	/**
	 * 
	 * @param observable
	 * @param object
	 */
	public void update(Observable observable, Object object) {
		
		if (observable instanceof RequiredRole){
			RequiredRole observingRole = ((RequiredRole)observable);
			ProvidedRole providedRole = findProvidedRole(observingRole);
			
			if (internalComponentProcessing != null){
				try {
					String results = (String)internalComponentProcessing.invoke(componentOrConnector, observingRole.getRoleValue());
					providedRole.setRoleValue(results);
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				}
			}else{			
				providedRole.setRoleValue(observingRole.getRoleValue());
			}
			Message.putInLogger("Passage Role requis-Role fournis\n" +					
				"- Role fournis active : " + providedRole.getClass().getSimpleName() + 
				", avec la valeur : " + providedRole.getRoleValue() +
				" (Connecteur proprietaire : " + providedRole.getOwner() + ")\n" +
				"- Role requis ecoute : " + observingRole.getClass().getSimpleName() +
				" (Connecteur proprietaire : " + observingRole.getOwner() + ")");
		}else if (observable instanceof ProvidedRole){
			ProvidedRole observingRole = ((ProvidedRole)observable);
			RequiredRole requiredRole = findRequiredRole(observingRole);
			
			if (internalComponentProcessing != null){
				try {
					Object results = internalComponentProcessing.invoke(componentOrConnector, observingRole.getRoleValue());
					requiredRole.setRoleValue(results.toString());
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				}
			}else{			
				requiredRole.setRoleValue(observingRole.getRoleValue());
			}
			
			Message.putInLogger("Passage Role fournis-Role requis\n" +					
				"- Role requis active : " + requiredRole.getClass().getSimpleName() + 
				", avec la valeur : " + requiredRole.getRoleValue() +
				" (Connecteur proprietaire : " + requiredRole.getOwner() + ")\n" +
				"- Role fournis ecoute : " + observingRole.getClass().getSimpleName() +
				" (Connecteur proprietaire : " + observingRole.getOwner() + ")");
		}		
	}	
}
